﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Perovich.GameObjects.Helpers;
using Microsoft.Xna.Framework;
using Perovich.GameObjects.Attributes;
using Perovich.GameObjects.Interfaces;
using Perovich.GameObjects.Tools.Util;
using System.CodeDom;
using Microsoft.Xna.Framework.Input;

namespace Perovich.GameObjects.Components
{
    [ComponentDependency(typeof(Position2D), typeof(Size2D))]
    [AutomaticImport("Perovich.GameObjects.Helpers", true)]
    [AutomaticProperty("IsHitTestVisible", "Clickable.GeneratesMouseClicks", XmlSummary = "Gets or sets a value indicating whether this entity responds to mouse clicks.", XmlReturns = "true if the entity responds to mouse clicks; false otherwise")]
    [AutomaticProperty("ClickTolerance", "Clickable.Tolerance", XmlSummary = "Gets or sets a value representing the entity's tolerance when responding to mouse clicks.", XmlReturns = "A <see cref=\"System.Single\">float</see> representing the tolerance used for click events.")]
    [AutomaticEvent(typeof(Clickable), "GenerateAutoEvent")]
    public sealed class Clickable : EntityComponent
    {
#if WINDOWS
        public static AutoEvent GenerateAutoEvent(CodeExpression me)
        {
            var target = new CodeEventReferenceExpression(me, "Clicked");
            var even = new AutoEvent("Click","EventArgs", target);
            even.Summary = "Signaled when the entity gets clicked.";
            return even;
        }
#endif

        private Position2D position;
        private Size2D size;

        public bool GeneratesMouseClicks
        {
            get;
            set;
        }

        public float Tolerance
        {
            get;
            set;
        }

        public event EventHandler<EventArgs> Clicked;
        

        public BoundingBox ClickBox
        {
            get
            {
                Vector2 pos = position.Position;
                return new BoundingBox(new Vector3(pos.X - size.Origin.X, pos.Y - size.Origin.Y, 0), new Vector3(pos.X - size.Origin.X + size.Width, pos.Y - size.Origin.Y + size.Height, 0));
            }
        }

        public Clickable()
        {
            Tolerance = 0;
            GeneratesMouseClicks = true;
        }

        public override void Initialize()
        {
            position = Owner.Find<Position2D>();
            size = Owner.Find<Size2D>();
            UpdateOrder = Constants.ClickableUpdateOrder;
            InternalMouseHelper.Init(this);
            base.Initialize();
        }

        void LeftButton_Up(object sender, MouseHelperEventArgs e)
        {
            if ((Owner.Enabled) && (GeneratesMouseClicks))
            {
                Vector2 position = new Vector2(e.State.X, e.State.Y);
                BoundingBox TouchBB = new BoundingBox(new Vector3(position.X - Tolerance, position.Y - Tolerance, 0),
                                                  new Vector3(position.X + Tolerance, position.Y + Tolerance, 0));

                if (ClickBox.Intersects(TouchBB))
                {
                    OnClick();
                }
            }
        }


        public override void Update(GameTime gameTime)
        {
            MouseState last_state, state;
            if (InternalMouseHelper.HasMouseChanged(this, out last_state, out state))
            {
                if ((state.LeftButton != last_state.LeftButton) && (state.LeftButton == ButtonState.Released))
                {
                    if (GeneratesMouseClicks)
                    {
                        Vector2 position = new Vector2(state.X, state.Y);
                        BoundingBox TouchBB = new BoundingBox(new Vector3(position.X - Tolerance, position.Y - Tolerance, 0),
                                                          new Vector3(position.X + Tolerance, position.Y + Tolerance, 0));

                        if (ClickBox.Intersects(TouchBB))
                        {
                            OnClick();
                        }
                    }
                }
            }
            base.Update(gameTime);
        }

        private void OnClick()
        {
            if (Clicked != null)
            {
                Clicked(this, new EventArgs());
            }
        }
    }
}
